<?
/**
 * Librería de funciones
 * Ultima modificacion: 08/01/2010 10:09:10 p.m.
 *
 */

/* FUNCTION LIST:
  Date:
   dateFormat
   getAgeByDate

  String escaping:
   escapePost
   fullescapePost
   messageUrlDecode
   messageUrlEncode

  Misc:
   multiarray_search
   limitWords
   select_gen
   showListPagination
   dateDiff
   htmlRedirect
   refresh
   stripDangerousHTMLTags
   urlseoencode
   isRFC3696ValidEmailAddress
*/

if(file_exists(DIR_INCLUDES."/functions.local.php")) require_once(DIR_INCLUDES."/functions.local.php");

/**
 * __autoload()
 *
 * Three possible class paths (checked in order):
 * <ol>
 * <li>./classes</li>
 * <li>DIR_ROOT/modules/MODULE_ID/classes</li>
 * <li>DIR_ROOT/admin/MODULE_ID/classes</li>
 * <li>DIR_CLASSES (usualy DIR_ROOT/includes/classes)</li>
 * </ol>
 */
function __autoload($class_name)
{
    // checking ./classes directory
    if (file_exists($_SERVER['DOCUMENT_ROOT'] . dirname($_SERVER['PHP_SELF']) ."/classes/". $class_name . ".php"))
    {
        require_once($_SERVER['DOCUMENT_ROOT'] . dirname($_SERVER['PHP_SELF']) ."/classes/". $class_name . ".php");
    }
    else
    {
        $moduleName = getModuleName($class_name);

        // checking DIR_ROOT/modules/MODULE_ID/classes directory
        if ($moduleName && file_exists(DIR_ROOT."/modules/". $moduleName ."/classes/". $class_name .".php"))
        {
            require_once(DIR_ROOT."/modules/". $moduleName ."/classes/". $class_name .".php");
        }

        // checking DIR_ROOT/admin/MODULE_ID/classes directory
        else if ($moduleName && file_exists(DIR_ROOT."/admin/". $moduleName ."/classes/". $class_name  .".php"))
        {
            require_once(DIR_ROOT."/admin/". $moduleName ."/classes/". $class_name .".php");
        }

        // checking DIR_CLASSES directory
        else if(file_exists(DIR_CLASSES ."/". $class_name . ".php"))
        {
            require_once(DIR_CLASSES ."/". $class_name . ".php");
        }

        // At this point the selected class doesn't exist for __autoload.
        else
        {
            $ar = debug_backtrace(__CLASS__);
            die("<b>ERROR WHILE IMPORTING CLASS: ". $class_name .".php</b><br>In <b>". $ar[1]['file'] ."</b> line <b>". $ar[1]['line'] ."</b> function <b>". $ar[1]['function'] ."</b>");
        }
    }
}

/** returns an array (of Module objects) available modules
  * The purpose es to encapsulate the access to $GLOBALS
  */
function getAllModules()
{
    $modules = array();
    $iniModules = array();
    $finalModules = array();
    foreach($GLOBALS["CONF"]["admin"]["modules"] as $m)
    {
        $module = new Module($m["id"]);
        switch($m['id'])
        {
            case "home"     : $iniModules[$m["id"]] = $module;
                                break;
            case "users"    : $finalModules[$m["id"]] = $module;
                                break;
            default         : $modules[$m["id"]] = $module;
        }
    }
    array_multisort($modules, SORT_ASC);
    $modules = array_merge($iniModules, $modules, $finalModules);
    return $modules;
}

function getAllRoles()
{
    global $dbLink;
    $roles = array();
    $sql = "SELECT roleID FROM users_roles";
    $result = mysql_query($sql, $dbLink);
    while($row = mysql_fetch_array($result)) $roles[] = new Role($row[0]);
    return $roles;
}

function registerModule($config, $configOpt=null)
{
    if(is_array($config))
    {
        $id = $config['id'];
    }
    else if(is_string($config))
    {
        $id = $config;
        $config = $configOpt;
    }
    else die('registerModule(): error passing argument 1.');

    if (!$config['id']) vd($config);
    if(!$config['id'] || !$config['name'])
    {
        die('registerModule(): id and name must be configured.');
    }

    $GLOBALS["CONF"]["admin"]["modules"][$id] = $config;

    // default values:
    if(!isset($GLOBALS["CONF"]["admin"]["modules"][$id]["url"]))
        $GLOBALS["CONF"]["admin"]["modules"][$id]["url"] = $GLOBALS["CONF"]["url"]["admin"] ."/".$id;
    if(!isset($GLOBALS["CONF"]["admin"]["modules"][$id]["numMaxListedRows"]))
        $GLOBALS["CONF"]["admin"]["modules"][$id]["numMaxListedRows"] = 40;
    if(!isset($GLOBALS["CONF"]["admin"]["modules"][$id]["numMaxListPages"]))
        $GLOBALS["CONF"]["admin"]["modules"][$id]["numMaxListPages"] = 15;
}

function isRegisteredModule($moduleID)
{
    return isset($GLOBALS["CONF"]["admin"]["modules"][$moduleID]);
}

function getModuleName($string)
{
    $split = preg_split("/(?<=[a-z]) (?=[A-Z])/x", $string);
    if(count($split)==0) return false;
    return $split[0];
}


/**
 * Loads the whole config
 * if a cacheconf file exists, it loads it and exits.
 */
function loadConfig()
{
    $GLOBALS['configLoaded']=false;
    $cachefname = DIR_FILE_UPLOAD ."/tmp/config.cache.php"; // admin/cacheconf
    if(file_exists($cachefname))
    {
        require($cachefname);
        $GLOBALS["CONF"] = unserialize(base64_decode($cacheConfig));
        unset($cacheConfig);
        $GLOBALS['configLoaded']=true;
    }
    else
    {
        $GLOBALS["CONF"]["admin"]["modules"] = array();
        // all modules config.php are in the admin and modules dir
        if (file_exists(DIR_MODULES))
        {
            $files = scandir(DIR_MODULES);
            foreach($files AS $file)
            {
                if($file == '.' || $file == '..') continue;
                $modulePath = DIR_MODULES .'/'. $file;
                if(is_dir($modulePath)) loadconfigfile($modulePath);
            }
        }
        if (file_exists(DIR_ADMIN))
        {
            $files = scandir(DIR_ADMIN);
            foreach($files AS $file)
            {
                if($file == '.' || $file == '..') continue;
                $modulePath = DIR_ADMIN .'/'. $file;
                if(is_dir($modulePath)) loadconfigfile($modulePath);
            }
        }
        // Writeing cache if the $GLOBALS["CONF"]["serialize"] option is setted true
        if(isset($GLOBALS["CONF"]["serialize"]))
        {
            $f = fopen($cachefname, "w");
            $cacheConfigContent .= "<? \$cacheConfig='". base64_encode(serialize($GLOBALS["CONF"])) ."'; ?>\n";
            fwrite($f, $cacheConfigContent);
            fclose($f);
        }
        $GLOBALS['configLoaded']=true;
    }
}

/**
 * Includes config.php or config.default.php if they exist.
 *
 */
function loadconfigfile($dir)
{
    $dir = trim($dir);
    if($dir{strlen($dir)-1}!="/") $dir .="/";

    if(file_exists($dir ."config.php"))
    {
        ob_start();
        require($dir ."config.php");
        $data=ob_get_contents();
        ob_end_clean();
        echo trim($data);
        return true;
    }
    else if(file_exists($dir ."config.default.php"))
    {
        require($dir ."config.default.php");
        return true;
    }
    else return false;
}

/**
 * connectDb
 * @return bool false|$dbLink
 */
function connectDb($new_link=false)
{
    $dbLink = @mysql_connect($GLOBALS["CONF"]["db"]["host"], $GLOBALS["CONF"]["db"]["user"], $GLOBALS["CONF"]["db"]["pass"], $new_link);
    if (!$dbLink)
    {
        print '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html>
               <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Sistema momentaneamente offline.</title><link rel="shortcut icon" href="http://www.adverit.com/images/favicon.ico" type="image/x-icon"><link rel="stylesheet" type="text/css" href="http://www.adverit.com/css/ispconfig.css"></head>
               <body><div class="box base"><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>&nbsp;</p><p>En este momento no se puede establecer conexión con la base de datos.</p><p><strong>Estamos trabajando para reestablecer el servicio.</strong></p>
               <p><strong>Por favor intente nuevamente en unos minutos. </strong></p><a href="http://www.adverit.com" target="_blank"><img src="http://www.adverit.com/images/ispconfig/logo.gif" class="logo" border="0"></a></div></body></html>';
        exit();
    }
    mysql_select_db($GLOBALS["CONF"]["db"]["database"], $dbLink);

    // Don't mess with collations!!
    // Added on 4/20/2008 10:34:26 PM by King Beto
    mysql_query("SET NAMES 'utf8'", $dbLink);
    mysql_query("SET collation_connection = 'utf8_general_ci'", $dbLink);
    mysql_query("SET CHARACTER SET 'utf8'", $dbLink);

    return $dbLink;
}

/**
* devuelve true si el array es asociativo
*/
function is_assoc($var)
{
    return is_array($var) && array_keys($var)!==range(0,sizeof($var)-1);
}

/**
 * Checks if the levelID passed has access to the module.
 */
function userModuleAccessLevelCheck($userAccessLevelID, $module)
{
    if (is_array($module['access_levels']))
    {
        return (array_search($userAccessLevelID, $module['access_levels']) !== false);
    }
    else return ($userAccessLevelID==$module['access_levels']);
}

// ***** DATE *****

/**
 * Returns a formated date.
 *
 * Example of usage:
 * <code>
 * echo dateFormat('2000-01-01', 'd/m/Y'); // outputs 01/01/2000
 * </code>
 * @return string formated date
 */
function dateFormat($date, $format = null, $offset = NULL)
{
    if(strtotime($date)==-62169968592) return "-";
    $format = $format? $format : $GLOBALS["CONF"]["date_format"];
    $time = strtotime($date) + $offset;
    return date($format, $time);
}

/**
 * Returns the age corresponding to a date.
 *
 * @return integer|bool age
 */
// Uncomment year/month/day below to test.
//    $date = "1919-06-29";
function getAgeByDate($date)
{
    $arDate = explode("-", $date);
    if (checkdate($arDate[1], $arDate[2], $arDate[0])) {
        $dob_date = str_replace("-", "", $date);
        $age = floor((date("Ymd")-intval($dob_date))/10000);
        if (($age < 0) or ($age > 114)) {
            return FALSE;
        }
        return $age;
    }
    return FALSE;
}


/**
 * Escapes the array items, ready for the mySQL query from an initial array, like $_POST or $_GET
 *
 * Example of usage:
 * <code>
 * $tmp = array("  1  ", "1'", "4'ad");
 * print_r(array_walk($tmp, 'escapePost'));
 * </code>
 *
 * outputs:
 * <code>
 *  array(
 *    [a] => 1
 *    [b] => 1
 *    [c] => 4
 *  )
 * </code>
 *
 * Second example:
 *
 * <code>
 * $tmp = array("  asdas  ", "asdq", "asd'ad");
 * print_r(array_walk($tmp, 'escapePost'));
 * </code>
 * Outputs:
 * <code>
 * array(
 *    [a] => asdas
 *    [b] => asdq
 *    [c] => asd\'ad
 * )
 * </code>
 *
 * @todo Si el array se pasa por referencia, es conveniente usarla con $_POST y $_GET??
 */
function escapePost(&$item, $key)
{
    if (!is_string($item)) return;
    $item = trim($item);
    $item = mysql_escape_string($item);
}

/**
 * Escapes the array items for a mySQL query. CLEANS ALL HTML!!!
 *
 * Example of usage:
 * <code>
 * $tmp = array("  asdas  ", "asdq", "asd'ad");
 * print_r(array_walk($tmp, 'fullescapePost'));
 * </code>
 * Outputs:
 * <code>
 * array(
 *    [a] => asdas
 *    [b] => asdq
 *    [c] => asd\'ad
 * )
 * </code>
 */
function fullescapePost(&$item, $key = null)
{
    $item = strip_tags($item);
    $item = trim($item);
    $item = mysql_escape_string($item);
}

/**
 * Returns a message encoded ready for sending through an url
 *
 * Example of usage:
 * <code>
 *  echo messageUrlEncode("Hello world!");                   // echoes SGVsbG8gd29ybGQh
 *  echo messageUrlDecode("SGVsbG8gd29ybGQh");               // echoes Hello world!
 *  echo messageUrlDecode(messageUrlEncode("Hello world!")); // echoes Hello world!
 * </code>
 *
 */
function messageUrlEncode($msg)
{
    return urlencode(base64_encode($msg));
}

/**
 * Decodes a message encoded with messageUrlEncode()
 *
 * Example:
 * @see messageUrlEncode()
 *
 */
function messageUrlDecode($msg)
{
    return strip_tags(base64_decode(urldecode($msg)));
}

/**
 * Cleans the string for database storage.
 *
 * @return string clean string
 */
function txt2sql($str, $striptags=false, $dbLink=null)
{
    if(get_magic_quotes_gpc()) $str = stripslashes($str);
    if (!$dbLink) global $dbLink;
    $str = trim($str);
    if ($striptags)
    {
        $str = strip_tags($str);
        $str = nl2br($str);
    }
    return mysql_real_escape_string($str, $dbLink);
}



//***** MISC *****

/**
 * Searches for an element in a multidimensional (bidimensional?) array
 *
 * Example of usage:
 * <code>
 * $myArr = array(
 *    13 =>  array( "fruit" => "banana"),
 *   654 =>  array( "fruit" => "apple" ),
 *   2445 => array("fruit" => "nothing else")
 * );
 *
 * echo multiarray_search($multiArray , "fruit", "apple"); //Output: 654
 * </code>
 *
 * @todo parece ser para arrays bidimensionales, ojo.
 *
 */
function multiarray_search($multiArray, $campo, $valor)
{
    if(!is_array($multiArray)) return false;

    while(isset($multiArray[key($multiArray)]))
    {
       if($multiArray[key($multiArray)][$campo]==$valor)
       {
           return key($multiArray);
       }
       next($multiArray);
    }
    return false;
}

/**
 * Returns a string with only the specified number of words from the source string.
 *
 * Example of usage:
 * <code>
 * $longtext = "This is a line of words. Some more words right here.";
 * // show just 6 words...
 * $shorttext = limitWords( $longtext, 6);
 * echo $shorttext;
 * </code>
 *
 */
function limitWords($str, $num, $strAppend = '')
{
    $words = preg_split( '/[\s]+/', $str, -1, PREG_SPLIT_OFFSET_CAPTURE );
    if( isset($words[$num][1]) )
    {
        $str = substr( $str, 0, $words[$num][1] );
    }
    return trim( $str ) . (count($words)>$num? $strAppend : "");
}

/**
=======
 * Returns a string with only the specified number of characters from the source string.
 *
 * Example of usage:
 * <code>
 * $longtext = "This is a line of words. Some more words right here.";
 * // show just 10 chars...
 * $shorttext = truncate( $longtext, 10);
 * echo $shorttext;
 * </code>
 *
 */
function truncate($str, $numOfChars)
{
    if(strlen($str) > $numOfChars)
    {
        $str = strip_tags($str); // DON'T WANT UNFINISHED CODE!!!!!!!!
        $str[$numOfChars] = '.';
        $str[$numOfChars +1] = '.';
        $str[$numOfChars +2] = '.';
        return substr($str,0,$numOfChars +3);
    }
    return $str;
}


/**
 * Date selector ui
 *
 * Resulting post variables sample:
 * <code>
 *  $_POST['inputname'] = "2008-03-05".
 *  $_POST['inputname_anio'] = "2008".
 *  $_POST['inputname_mes'] = "03".
 *  $_POST['inputname_dia'] = "05".
 * </code>
 * @author Larra <jastelarra@adverit.com>
 * @param date $date Date In which the selector will be. Default: today.
 * @param string $inputName The variable name which will be created. Default: "date"
 * @param string $className CSS class name for the select tags.
 * @param integer $yOffsetUp Year Offset Up: Amount of years the select will have above current year.
 * @param integer $yOffsetDown Year Offset Down: Amount of years the select will have below current year.
 * @param bool $withCalendar Set it false if a calendar must not be included
 * @param bool $withHours: Includes hour selector.
 * @param bool $usaMode: Month comes first.
 */
function selectDates($date, $inputName = "", $className = "", $yOffsetUp = 10, $yOffsetDown = 25, $withCalendar=true, $withHours = false, $usaMode = false)
{
    list($aniomesdia, $horaminseg) = split(" ", $date);  // quito hora:minuto:segundo
    list($año, $mes, $dia) = split("-", $aniomesdia); //separo la fecha.
    list($hora, $min, $seg) = split(":", $horaminseg); //separo la hora.
    $inputName = $inputName ? $inputName : "date";
    $topRange = (int)date('Y') + $yOffsetUp;
    $bottomRange = (int)date('Y') - $yOffsetDown;

    // Day
    $dayStr = "<select name=\"".$inputName."_dia\"  id=\"".$inputName."_dia\" class=\"". $className ."\"  onChange=\"setDays('".$inputName."');updateCalendar('".$inputName."','".($withHours ? "1" : "0")."');\">\n";
    for($i = 1; $i <= 31 ;$i++)
    {
        $i = sprintf("%02d", $i);
        $dayStr .= "<option value=\"". $i ."\" ". ($dia==$i? "selected" : "") .">". $i ."</option>\n";
    }
    $dayStr .= "</select>";

    // Month
    $monthStr = "<select name=\"".$inputName."_mes\" id=\"".$inputName."_mes\" class=\"". $className ."\"  onChange=\"setDays('".$inputName."');updateCalendar('".$inputName."','".($withHours ? "1" : "0")."');\">\n";
    for($i = 1; $i <= 12; $i++)
    {
        $i = sprintf("%02d", $i);
        $monthStr .= "<option value=\"". $i ."\" ". ($mes==$i? "selected" : "") .">". $i ."</option>\n";
    }
    $monthStr .= "</select>";

    // Year
    $yearStr = "<select name=\"".$inputName."_anio\" id=\"".$inputName."_anio\" class=\"". $className ."\"  onChange=\"setDays('".$inputName."');updateCalendar('".$inputName."','".($withHours ? "1" : "0")."');\">\n";
    for( $i=$topRange;$i>$bottomRange;$i--)
    {
        $yearStr .= "<option value=\"". $i ."\" ". ((int)$año==$i? "selected" : "") .">". $i ."</option>\n";
    }
    $yearStr .= "</select>";

    if($usaMode)
    {
        echo $monthStr;
        echo $dayStr;
        echo $yearStr;
    }
    else
    {
        echo $dayStr;
        echo $monthStr;
        echo $yearStr;
    }

    echo "<input type='hidden' name='".$inputName."' id='".$inputName."' value='".$date."' onChange=\"updateSelector('".$inputName."'); setDays('".$inputName."');updateCalendar('".$inputName."','".($withHours ? "1" : "0")."');\">";
    echo '<script type="text/javascript" src="'.$GLOBALS['CONF']["url"]["js"].'/lib/calendar/selectdates.js.php?yOffsetUp='. $yOffsetUp .'"></script>'."\n";

    if ($withCalendar===true)
    {
        echo '<img src="'.$GLOBALS['CONF']["url"]["js"].'/lib/calendar/img.gif" id="'.$inputName.'_but" style="cursor: pointer;" title="Date selector" />';
        if(!$GLOBALS['selectedDays'])
        {
            echo "\n\t\t".'<style>@import "'. $GLOBALS["CONF"]["url"]["js"] .'/lib/calendar/calendar-blue";</style>
                <script language="JavaScript" type="text/javascript" src="'.$GLOBALS['CONF']["url"]["js"].'/lib/calendar/calendar.js"></script>
                <script language="JavaScript" type="text/javascript" src="'.$GLOBALS['CONF']["url"]["js"].'/lib/calendar/calendar-setup.js"></script> <!-- main calendar program -->
                <script type="text/javascript" src="'.$GLOBALS['CONF']["url"]["js"].'/lib/calendar/lang/calendar-en.js"></script>';
        }
        echo "\n\t\t".'<script type="text/javascript">
            Calendar.setup({
            inputField  :    "'.$inputName.'",
            ifFormat    :    "%Y-%m-%d",
            showsTime   :    false,
            button      :    "'.$inputName.'_but",
            cache       : true,
            range       : ['.$bottomRange.','.$topRange.']
            });</script>';

        $GLOBALS["selectedDays"] = true;
    }
    if($withHours)
    {
        echo "Hr. <select name=\"".$inputName."_hora\" id=\"".$inputName."_hora\" class=\"". $className ."\"  onChange=\"setDays('".$inputName."');updateCalendar('".$inputName."','".($withHours ? "1" : "0")."');\">\n";
        for( $i=0;$i < 24;$i++)
        {
            $i = sprintf("%02d", $i);
            echo "<option value=\"". $i ."\" ". ((int)$hora==$i? "selected" : "") .">". $i ."</option>\n";
        }
        echo "</select>";

        echo "<select name=\"".$inputName."_min\" id=\"".$inputName."_min\" class=\"". $className ."\"  onChange=\"setDays('".$inputName."');updateCalendar('".$inputName."','".($withHours ? "1" : "0")."');\">\n";
        for( $i=0;$i < 60;$i++)
        {
            $i = sprintf("%02d", $i);
            echo "<option value=\"". $i ."\" ". ((int)$min==$i? "selected" : "") .">". $i ."</option>\n";
        }
        echo "</select>";

        echo "<select name=\"".$inputName."_seg\" id=\"".$inputName."_seg\" class=\"". $className ."\"  onChange=\"setDays('".$inputName."');updateCalendar('".$inputName."','".($withHours ? "1" : "0")."');\">\n";
        for( $i=0;$i < 60;$i++)
        {
            $i = sprintf("%02d", $i);
            echo "<option value=\"". $i ."\" ". ((int)$seg==$i? "selected" : "") .">". $i ."</option>\n";
        }
        echo "</select>";
    }
    echo '<script>updateCalendar("'.$inputName.'","'.($withHours ? "1" : "0").'");</script>';
}

function selectDateTimes($date, $inputName = "", $className = "", $yOffsetUp = 10, $yOffsetDown = 25, $withCalendar=true)
{
    selectDates($date, $inputName, $className, $yOffsetUp, $yOffsetDown, $withCalendar, true);
}

function selectDateTimesUSA($date, $inputName = "", $className = "", $yOffsetUp = 10, $yOffsetDown = 25, $withCalendar=true)
{
    selectDates($date, $inputName, $className, $yOffsetUp, $yOffsetDown, $withCalendar, true, true);
}

function selectDatesUSA($date, $inputName = "", $className = "", $yOffsetUp = 10, $yOffsetDown = 25, $withCalendar=true)
{
    selectDates($date, $inputName, $className, $yOffsetUp, $yOffsetDown, $withCalendar, false, true);
}

/**
 * Shows the number of pages available in a listing table.
 *
 */
function showListPagination($urlVars, $numTotalRows, $position=null, $numMaxListedRows=null, $url='')
{
    echo getListPagination($urlVars, $numTotalRows, $position, $numMaxListedRows, $url);
}


/**
 * Gets the html for the the number of pages available in a listing table.
 *
 */
function getListPagination($urlVars, $numTotalRows, $position=null, $numMaxListedRows=null, $url='')
{
    $urlVars = htmlentities($urlVars);
    $position = $position? $position : $_GET['position'];
    $numMaxListedRows = $numMaxListedRows? $numMaxListedRows : NUM_MAX_LISTED_ROWS;
    $numPages = (int) ceil($numTotalRows/$numMaxListedRows);
    $currentPage = (int) ceil($position/$numMaxListedRows)+1;
    $initial = (floor($position/(NUM_MAX_LIST_PAGES*$numMaxListedRows))) * NUM_MAX_LIST_PAGES + 1;
    $htmlString = '<ul class="pagination pagination-small m-t-none m-b-none">';
    $url = $url? $url : $_SERVER['PHP_SELF'];

    if( ($initial-1)*$numMaxListedRows >= $numMaxListedRows*NUM_MAX_LIST_PAGES )
    {
        $htmlString .= '<li><a href="'. $url ."?position=". (($initial-2)*$numMaxListedRows) . ($urlVars? "&amp;".$urlVars : "") ."\"><i class='icon-chevron-left'></i></a></li>";
    }

    for($i=$initial; $i<=$numPages && $i<$initial + NUM_MAX_LIST_PAGES; $i++)
    {
        if($i!=$currentPage)
        {
            $tmp = (($i-1)*$numMaxListedRows);
            $htmlString .= "<li><a href=\"". $url . "?".$urlVars. ($tmp>0? "&amp;position=".$tmp : "" ) .'">'.$i.'</a></li>';
        }
        else
        {
            $htmlString .= '<li class="active"><a href="#">'.$i.'</a></li>';
        }
    }
    $htmlString .= $i<=$numPages? "<a href=\"". $url . "?position=".(($i-1)*$numMaxListedRows). ($urlVars? "&amp;".$urlVars : "") ."\"><i class='icon-chevron-right'></i></a></ul>" : "</ul>";

    return $htmlString;
}


/**
 * Retuns a unique activation code.
 *
 * Returns an md5 encoded random number.
 *
 */
function makeActivationCode()
{
    return md5(strval(rand(1000000,9999999))."-".strval(microtime()));
}

/**
 * Returns the number of stars specified in html.
 *
 */
function getStarsFromNumber($number, $starsUrl='')
{
    $starsUrl = $starsUrl? $starsUrl : $GLOBALS["CONF"]["url"]["root"] ."/images/common";
    $stars = '';
    for ($i=0; $i < floor($number); $i++)
    {
        $stars .= '<img src="'. $starsUrl .'/ico_star_full.gif" alt="Start">';
    }

    // coma!
    $coma = round($number, 1)-(int)$number;
    if ($coma!=0)
    {
        if ($coma>0.5) $stars .= '<img src="'. $starsUrl .'/ico_star_full.gif" alt="Start">';
        else if ($coma<0.5) $stars .= '<img src="'. $starsUrl .'/ico_star_empty.gif" alt="Start">';
        else $stars .= '<img src="'. $starsUrl .'/ico_star_half.gif" alt="Start">';
    }

    for ($i=0; $i < (5-ceil($number)); $i++)
    {
        $stars .= '<img src="'. $starsUrl .'/ico_star_empty.gif" alt="Start">';
    }
    return $stars;
}

/**
 * Converts the string to Upper case.
 */
function fullUpper($string)
{
  $new_string = "";
  while (preg_match("/^([^&]*)(&)(.)([a-z0-9]{2,9};|&)(.*)/", $string, $regs))
  {
    $entity = $regs[2].strtoupper($regs[3]).$regs[4];
    if (html_entity_decode($entity)==$entity)
      $new_string .= strtoupper($regs[1]).$regs[2].$regs[3].$regs[4];
    else
      $new_string .= strtoupper($regs[1]).$entity;
    $string = $regs[5];
  }
  $new_string .= strtoupper($string);
  return $new_string;
}

/*
 * Outputs the HTML code that redirects via HTTP-EQUIV refresh.
 *
 * @param string $url the url where the browser will be redirected.
 * Be aware that leaving it blank will reload the page indefinitively.
 *
 */
function htmlRedirect($url)
{
    echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
    echo '<html xmlns="http://www.w3.org/1999/xhtml">';
    echo '<head>';
    echo '<META HTTP-EQUIV="Refresh" CONTENT="0; URL='. $url .'">';
    echo '<META HTTP-EQUIV="Pragma" CONTENT="no-cache">';
    echo '<meta http-equiv="cache-control" content="no-cache">';
    echo '<title>'.$GLOBALS["website"]["name"].'</title>';
    echo '</head><body></body></html>';
    exit(0);
}

/**
 * refresh Avoids the $_POST.
 *
 * @param bool $maintainGet If true, it uses the current $_GET data.
 * @param $getVars New $_GET variables
 * If you wish to change $_GET vars:
 * <code>
 * refresh(false) // NO VARS.
 * refresh(false, 'id=1&action=x..') // refresh WITH CUSTOM $_GET VARS.
 * </code>
 * @todo mejorar descripción
 */
function refresh($maintainGet = true, $getVars = NULL)
{
    if($maintainGet)
    {
        $getVars = $_SERVER['QUERY_STRING']."&".$getVars;
    }
    htmlRedirect($_SERVER['PHP_SELF']."?".$getVars);
}


/**
 * Calculates the difference between 2 dates. Takes leap years and DST into consideration. Accepts string date or timestamp as arguments.
 *
 * Example of usage:
 *
 * The result is not exactly 1 year (less 1 hour) since Nov 1, 2006 is not DST while Nov 1, 2007 is DST.
 * <code>
 * $a = dateDiff("2006-11-01", "2007-11-01");
 * print_r($a);
 * </code>
 * Outputs:
 * <code>
 * Array
 * (
 *     [years] => 0
 *     [months_total] => 11
 *     [months] => 11
 *     [days_total] => 364
 *     [days] => 30
 *     [hours_total] => 8759
 *     [hours] => 23
 *     [minutes_total] => 525540
 *     [minutes] => 0
 *     [seconds_total] => 31532400
 *     [seconds] => 0
 * )
 * </code>
 */
function dateDiff($d1, $d2)
{
    $d1 = (is_string($d1) ? strtotime($d1) : $d1);
    $d2 = (is_string($d2) ? strtotime($d2) : $d2);

    $diff_secs = abs($d1 - $d2);
    $base_year = min(date("Y", $d1), date("Y", $d2));

    $diff = mktime(0, 0, $diff_secs, 1, 1, $base_year);
    return array("years" => date("Y", $diff) - $base_year,
                 "months_total" => (date("Y", $diff) - $base_year) * 12 + date("n", $diff) - 1,
                 "months" => date("n", $diff) - 1,
                 "days_total" => floor($diff_secs / (3600 * 24)),
                 "days" => date("j", $diff) - 1,
                 "hours_total" => floor($diff_secs / 3600),
                 "hours" => date("G", $diff),
                 "minutes_total" => floor($diff_secs / 60),
                 "minutes" => (int) date("i", $diff),
                 "seconds_total" => $diff_secs,
                 "seconds" => (int) date("s", $diff));
}

/*
** returns int > 0 if d1 > d2, int = 0 if equal, int = -1 if d2 > d1.
*/
function compareDates($d1, $d2)
{
    $d1 = (is_string($d1) ? strtotime($d1) : $d1);
    $d2 = (is_string($d2) ? strtotime($d2) : $d2);
    return $d1 - $d2;
}

/**
 * Strips dangerous HTML Tags from the string
 *
 */
function stripDangerousHTMLTags($text)
{
    // still have work on this!!!: href="javascript:", onclick="", onmouseover="" etc mus be removed.

    // html and body tags
    preg_replace("/<html[^>]*>/", "", $text);
    preg_replace("/</html>/", "", $text);
    preg_replace("/<body[^>]*>/", "", $text);
    preg_replace("/</body>/", "", $text);

    // Don't forget selft closing script tags
    preg_replace("/<\!DOCTYPE[^>]*>/", "", $text);
    preg_replace("/<link[^>]*>/", "", $text);
    preg_replace("/<script[^>]*>/", "", $text);

    // The rest
    $text = preg_replace(
        array(
            // Remove invisible content
            '@<head[^>]*?>.*?</head>@siu',
            '@<style[^>]*?>.*?</style>@siu',
            '@<script[^>]*?.*?</script>@siu',
            '@<object[^>]*?.*?</object>@siu',
            '@<embed[^>]*?.*?</embed>@siu',
            '@<applet[^>]*?.*?</applet>@siu',
            '@<noframes[^>]*?.*?</noframes>@siu',
            '@<noscript[^>]*?.*?</noscript>@siu',
            '@<noembed[^>]*?.*?</noembed>@siu',
            // Add line breaks before and after blocks
            '@</?((address)|(blockquote)|(center)|(del))@iu',
            '@</?((div)|(h[1-9])|(ins)|(isindex)|(p)|(pre))@iu',
            '@</?((dir)|(dl)|(dt)|(dd)|(li)|(menu)|(ol)|(ul))@iu',
            '@</?((table)|(th)|(td)|(caption))@iu',
            '@</?((form)|(button)|(fieldset)|(legend)|(input))@iu',
            '@</?((label)|(select)|(optgroup)|(option)|(textarea))@iu',
            '@</?((frameset)|(frame)|(iframe))@iu'),
        array(
            // Remove invisible content
            ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
            // Add line breaks before and after blocks
            "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0",
            "\n\$0", "\n\$0"),
        $text );

    return $text;
}


function getCountryByIp($addr, $dbLink)
{
    // Get the surfer's ip address
    // $addr = getenv("REMOTE_ADDR");
    // this sprintf() wrapper is needed, because the PHP long is signed by default
    $ip = sprintf("%u", ip2long($addr));

    $query =  "SELECT cc FROM `geoip` WHERE end >= $ip order by end asc limit 1";
    $result = mysql_query($query, $dbLink);
    list($country) = mysql_fetch_row($result);
    return $country;
}


function getLoginformUri($vars='', $requestUri = '')
{
    return $GLOBALS["CONF"]["url"]["root"] ."/loginform.php?loginRequestUri=". messageUrlEncode(($requestUri ? $requestUri : $_SERVER["REQUEST_URI"]) . $vars);
}


function getPageTitle($pageTitle ='')
{
    if ($pageTitle) return $pageTitle;
    $ommitedTitles = array("index.php","details.php", "abm.php");

    $scriptUrl = str_replace(dirname($_SERVER["SCRIPT_NAME"])."/", "", $_SERVER["SCRIPT_NAME"]);
    if ( in_array($scriptUrl, $ommitedTitles))
    {
        $dirs = explode("/", $_SERVER["SCRIPT_NAME"]);
        $title = $dirs[count($dirs)-2];
    }
    else $title = $scriptUrl;
    $title = str_replace(".php", "", $title);
    $title = str_replace("-", " ", $title);
    $title = str_replace("_", " ", $title);
    $title = ucwords($title);
    return $title;
}


function admin_url() { return $GLOBALS["CONF"]["url"]["admin"]; }
function base_url() { return $GLOBALS["CONF"]["url"]["root"]; }
function js_url() { return base_url()."/js"; }
function js()
{
    for($i = 0; $i < func_num_args(); $i++) $o .=  '<script type="text/javascript" src="'.func_get_arg($i).'"></script>'."\n";
    return $o;
}
function css()
{
    for($i = 0; $i < func_num_args(); $i++) $o .= '<link rel="stylesheet" type="text/css" href="'.func_get_arg($i).'"></link>'."\n";
    return $o;
}
function jquery($o="")
{
    //$o .= '<script type="text/javascript" src="'. js_url() .'/lib/jquery-1.7.1.min.js"></script>'."\n";
    $o .= '<script type="text/javascript" src="'. js_url() .'/lib/jquery-ui-1.10.3.custom/js/jquery-1.9.1.js"></script>'."\n";
    return $o;
}
function jqueryui($o="")
{
    /*$o .= '<script type="text/javascript" src="'. js_url() .'/lib/jquery-ui-1.8.18.custom/jquery-ui-1.8.18.custom.min.js"></script>'."\n";
    $o .= '<link rel="stylesheet" type="text/css" href="'. js_url() .'/lib/jquery-ui-1.8.18.custom/css/custom-theme/jquery-ui-1.8.18.custom.css"></link>'."\n";*/
    $o .= '<script type="text/javascript" src="'. js_url() .'/lib/jquery-ui-1.10.3.custom/js/jquery-ui-1.10.3.custom.js"></script>'."\n";
    $o .= '<link rel="stylesheet" type="text/css" href="'. js_url() .'/lib/jquery-ui-1.10.3.custom/css/smoothness/jquery-ui-1.10.3.custom.css"></link>'."\n";
    return $o;
}



// RFC3696 Email Parser by Cal Henderson <cal@iamcal.com>
function isRFC3696ValidEmailAddress($email)
{
    $no_ws_ctl = "[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]";
    $alpha = "[\\x41-\\x5a\\x61-\\x7a]";
    $digit = "[\\x30-\\x39]";
    $cr = "\\x0d";
    $lf = "\\x0a";
    $crlf = "(?:$cr$lf)";

    $obs_char = "[\\x00-\\x09\\x0b\\x0c\\x0e-\\x7f]";
    $obs_text = "(?:$lf*$cr*(?:$obs_char$lf*$cr*)*)";
    $text = "(?:[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f]|$obs_text)";

    $text = "(?:$lf*$cr*$obs_char$lf*$cr*)";
    $obs_qp = "(?:\\x5c[\\x00-\\x7f])";
    $quoted_pair = "(?:\\x5c$text|$obs_qp)";

    $wsp = "[\\x20\\x09]";
    $obs_fws = "(?:$wsp+(?:$crlf$wsp+)*)";
    $fws = "(?:(?:(?:$wsp*$crlf)?$wsp+)|$obs_fws)";
    $ctext = "(?:$no_ws_ctl|[\\x21-\\x27\\x2A-\\x5b\\x5d-\\x7e])";
    $ccontent = "(?:$ctext|$quoted_pair)";
    $comment = "(?:\\x28(?:$fws?$ccontent)*$fws?\\x29)";
    $cfws = "(?:(?:$fws?$comment)*(?:$fws?$comment|$fws))";

    $outer_ccontent_dull = "(?:$fws?$ctext|$quoted_pair)";
    $outer_ccontent_nest = "(?:$fws?$comment)";
    $outer_comment = "(?:\\x28$outer_ccontent_dull*(?:$outer_ccontent_nest$outer_ccontent_dull*)+$fws?\\x29)";

    $atext = "(?:$alpha|$digit|[\\x21\\x23-\\x27\\x2a\\x2b\\x2d\\x2f\\x3d\\x3f\\x5e\\x5f\\x60\\x7b-\\x7e])";
    $atom = "(?:$cfws?(?:$atext)+$cfws?)";

    $qtext = "(?:$no_ws_ctl|[\\x21\\x23-\\x5b\\x5d-\\x7e])";
    $qcontent = "(?:$qtext|$quoted_pair)";
    $quoted_string = "(?:$cfws?\\x22(?:$fws?$qcontent)*$fws?\\x22$cfws?)";

    $quoted_string = "(?:$cfws?\\x22(?:$fws?$qcontent)+$fws?\\x22$cfws?)";
    $word = "(?:$atom|$quoted_string)";

    $obs_local_part = "(?:$word(?:\\x2e$word)*)";
    $obs_domain = "(?:$atom(?:\\x2e$atom)*)";

    $dot_atom_text = "(?:$atext+(?:\\x2e$atext+)*)";
    $dot_atom = "(?:$cfws?$dot_atom_text$cfws?)";

    $dtext = "(?:$no_ws_ctl|[\\x21-\\x5a\\x5e-\\x7e])";
    $dcontent = "(?:$dtext|$quoted_pair)";
    $domain_literal = "(?:$cfws?\\x5b(?:$fws?$dcontent)*$fws?\\x5d$cfws?)";

    $local_part = "(($dot_atom)|($quoted_string)|($obs_local_part))";
    $domain = "(($dot_atom)|($domain_literal)|($obs_domain))";
    $addr_spec = "$local_part\\x40$domain";

    // see http://www.dominicsayers.com/isemail/ for details, but this should probably be 254
    if (strlen($email) > 256) return 0;
    // we need to strip nested comments first - we replace them with a simple comment
    $email = RFC3696StripComments($outer_comment, $email, "(x)");
    // now match what's left
    if (!preg_match("!^$addr_spec$!", $email, $m)) return 0;

    $bits = array('local' => isset($m[1]) ? $m[1] : '',
                  'local-atom' => isset($m[2]) ? $m[2] : '',
                  'local-quoted' => isset($m[3]) ? $m[3] : '',
                  'local-obs' => isset($m[4]) ? $m[4] : '',
                  'domain' => isset($m[5]) ? $m[5] : '',
                  'domain-atom' => isset($m[6]) ? $m[6] : '',
                  'domain-literal' => isset($m[7]) ? $m[7] : '',
                  'domain-obs' => isset($m[8]) ? $m[8] : '');

    // we need to now strip comments from $bits[local] and $bits[domain], for checking IPs, label sizes, etc
    $bits['local'] = RFC3696StripComments($comment, $bits['local']);
    $bits['domain'] = RFC3696StripComments($comment, $bits['domain']);

    if (strlen($bits['local']) > 64) return 0;
    if (strlen($bits['domain']) > 255) return 0;
    if (strlen($bits['domain-literal']))
    {
        $Snum = "(\d{1,3})";
        $IPv4_address_literal = "$Snum\.$Snum\.$Snum\.$Snum";
        $IPv6_hex = "(?:[0-9a-fA-F]{1,4})";
        $IPv6_full = "IPv6\:$IPv6_hex(:?\:$IPv6_hex){7}";
        $IPv6_comp_part = "(?:$IPv6_hex(?:\:$IPv6_hex){0,5})?";
        $IPv6_comp = "IPv6\:($IPv6_comp_part\:\:$IPv6_comp_part)";
        $IPv6v4_full = "IPv6\:$IPv6_hex(?:\:$IPv6_hex){5}\:$IPv4_address_literal";
        $IPv6v4_comp_part = "$IPv6_hex(?:\:$IPv6_hex){0,3}";
        $IPv6v4_comp = "IPv6\:((?:$IPv6v4_comp_part)?\:\:(?:$IPv6v4_comp_part\:)?)$IPv4_address_literal";

        // IPv4 is simple
        if (preg_match("!^\[$IPv4_address_literal\]$!", $bits['domain'], $m))
        {
            if (intval($m[1]) > 255) return 0;
            if (intval($m[2]) > 255) return 0;
            if (intval($m[3]) > 255) return 0;
            if (intval($m[4]) > 255) return 0;
        }
        else
        {
            // this should be IPv6 - a bunch of tests are needed here :)
            while(1)
            {
                if (preg_match("!^\[$IPv6_full\]$!", $bits['domain'])) break;

                if (preg_match("!^\[$IPv6_comp\]$!", $bits['domain'], $m))
                {
                    list($a, $b) = explode('::', $m[1]);
                    $folded = (strlen($a) && strlen($b)) ? "$a:$b" : "$a$b";
                    $groups = explode(':', $folded);
                    if (count($groups) > 6) return 0;
                    break;
                }

                if (preg_match("!^\[$IPv6v4_full\]$!", $bits['domain'], $m))
                {
                    if (intval($m[1]) > 255) return 0;
                    if (intval($m[2]) > 255) return 0;
                    if (intval($m[3]) > 255) return 0;
                    if (intval($m[4]) > 255) return 0;
                    break;
                }

                if (preg_match("!^\[$IPv6v4_comp\]$!", $bits['domain'], $m))
                {
                    list($a, $b) = explode('::', $m[1]);
                    $b = substr($b, 0, -1); # remove the trailing colon before the IPv4 address
                    $folded = (strlen($a) && strlen($b)) ? "$a:$b" : "$a$b";
                    $groups = explode(':', $folded);
                    if (count($groups) > 4) return 0;
                    break;
                }
                return 0;
            }
        }
    }
    else
    {
        // the domain is either dot-atom or obs-domain - either way, it's made up of simple labels and we split on dots
        $labels = explode('.', $bits['domain']);
        if (count($labels)==1) return 0;
        foreach ($labels as $label)
        {
            if (strlen($label) > 63) return 0;
            if (substr($label, 0, 1)=='-') return 0;
            if (substr($label, -1)=='-') return 0;
        }
        if (preg_match('!^[0-9]+$!', array_pop($labels))) return 0;
    }
    return 1;
}


// Private function for email validation.
function RFC3696StripComments($comment, $email, $replace='')
{
    while(1)
    {
        $new = preg_replace("!$comment!", $replace, $email);
        if (strlen($new)==strlen($email)) return $email;
        $email = $new;
    }
}

function urlseoencode($text)
{
    $normalizeChars= array(
        'Š'=>'S', 'š'=>'s', 'Ð'=>'Dj','Ž'=>'Z', 'ž'=>'z', 'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A',
        'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I',
        'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U',
        'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss','à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a',
        'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e', 'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i',
        'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o', 'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u',
        'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b', 'ÿ'=>'y', 'ƒ'=>'f'
    );

    $text = strtr($text, $normalizeChars);
    $text = strtolower($text);
    $text = preg_replace("/[^a-z0-9 _]/","",$text);
    $text = str_replace('&', '-and-', $text);
    $text = trim(preg_replace('/[^\w\d_ -]/si', '', $text));//remove all illegal chars
    $text = str_replace(' ', '-', $text);
    $text = str_replace('--', '-', $text);
    return $text;
}

function view($path, $object=array(), $echo = true) {
    global $GLOBALS;

    if(!$echo) ob_start();
    extract((array)$object);
    include $path;
    if($echo) return;
    $content = ob_get_contents();
    ob_end_clean();

    return $content;
}

?>
